package com.health.admin.config;

import com.health.admin.filter.CheckTokenFilter;
import com.health.admin.handler.*;
import com.health.security.impl.AdminDetailsService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * 后台管理系统安全配置
 * @author: zipeng Li
 * 2021/6/13  12:58
 */
@Configuration
@Order(100)
public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private AdminDetailsService adminDetailsService;
    @Resource
    private LoginSuccessHandler loginSuccessHandler;
    @Resource
    private LoginFailureHandler loginFailureHandler;
    @Resource
    private AdminAuthenticationEntryPoint adminAuthenticationEntryPoint;
    @Resource
    private AdminAccessDeniedHandler adminAccessDeniedHandler;
    @Resource
    private AdminLogoutSuccessHandler adminLogoutSuccessHandler;
    @Resource
    private CheckTokenFilter checkTokenFilter;
    @Value("${system.admin.login-url}")
    private String loginUrl;
    @Value("${system.admin.logout-url}")
    private String logoutUrl;

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 明文+随机盐值》加密存储
        return new BCryptPasswordEncoder();
    }


    /**
     * 配置权限资源
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // 只拦截检查'/api/admin/**'的请求
            .antMatcher("/api/admin/**").authorizeRequests()
                .antMatchers(loginUrl, "/api/admin/image","/api/admin/testMq").permitAll()
                .anyRequest().hasAuthority("ADMIN")
            .and().formLogin()
                .loginProcessingUrl(loginUrl)
                //　自定义的登录验证成功或失败后的去向
                .successHandler(loginSuccessHandler)
                .failureHandler(loginFailureHandler)
            .and().logout()
                .logoutUrl(logoutUrl)
                .logoutSuccessHandler(adminLogoutSuccessHandler)
                // 禁用csrf防御机制(跨域请求伪造)，这么做在测试和开发会比较方便。
            .and().csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .exceptionHandling()
                .authenticationEntryPoint(adminAuthenticationEntryPoint)
                .accessDeniedHandler(adminAccessDeniedHandler);
        http.addFilterBefore(checkTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 配置认证处理器
     * 自定义的UserDetailsService
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(adminDetailsService);
    }
}
